use std::{iter::once, vec};

use crate::descriptor::field_descriptor_proto::Label;
use swc_common::DUMMY_SP;
use swc_ecma_ast::*;
use swc_ecma_ast::{MemberExpr, MemberProp, IfStmt, ReturnStmt, Lit,
    Accessibility, BinaryOp, Class, ClassMember, ClassMethod, Decl, Decorator, ExportDecl, Expr,
    MethodKind, ModuleDecl, ModuleItem, Param, PropName, Stmt,
    TsEntityName, TsExprWithTypeArgs, TsType, TsTypeAnn, TsTypeRef,
};
use swc_ecma_utils::quote_ident;
use heck::{ToLowerCamelCase, ToUpperCamelCase};
use crate::{
    context::{Context, PropPos, Syntax},
    descriptor::{
        self, field_descriptor_proto::Type, DescriptorProto, FieldDescriptorProto,
    },
};
use super::{
    common::{normalize_name, normalize_type_name, ns_name},
    LarkPbRuntime,
};

impl LarkPbRuntime {
    pub(super) fn print_verify(
        &self,
        ctx: &mut Context,
        descriptor: &DescriptorProto,
        ns: &mut Vec<String>,
    ) -> ModuleItem {
        let lark = ctx.get_import(Self::LARK_PACKAGE, Some(Self::LARK_PACKAGE_NAME));
        let interface_type = ctx.lazy_decl_type_ref(&ns_name(ns, descriptor.name()), PropPos::Interface);
    
        // 实现 Verifier 接口
        let implement: TsExprWithTypeArgs = TsExprWithTypeArgs {
            span: DUMMY_SP,
            expr: Box::new(crate::member_expr!(lark, "Verifier")),
            type_args: Some(Box::new(swc_ecma_ast::TsTypeParamInstantiation {
                span: DUMMY_SP,
                params: vec![
            Box::new(TsType::TsTypeRef(TsTypeRef {
                span: DUMMY_SP,
                type_name: TsEntityName::Ident(Ident::new("Record".into(), DUMMY_SP)),
                type_params: Some(Box::new(TsTypeParamInstantiation {
                    span: DUMMY_SP,
                    params: vec![
                        // string type
                        Box::new(TsType::TsKeywordType(TsKeywordType {
                            span: DUMMY_SP,
                            kind: TsKeywordTypeKind::TsStringKeyword,
                        })),
                        // ESObject type
                        Box::new(TsType::TsTypeRef(TsTypeRef {
                            span: DUMMY_SP,
                            type_name: TsEntityName::Ident(Ident::new("ESObject".into(), DUMMY_SP)),
                            type_params: None,
                        })),
                    ],
                })),
            })),
        ],
                // params: vec![Box::new(TsType::TsTypeRef(TsTypeRef {
                //     span: DUMMY_SP,
                //     type_name: TsEntityName::Ident(interface_type.clone()),
                //     type_params: None,
                // }))],
            })),
        };
    
        // 生成验证逻辑的语句
        let stmts = self.verify_setup_inner(ctx, descriptor, ns);
    
        // 定义 verify 方法
        let verify_method = ClassMethod {
            span: DUMMY_SP,
            key: PropName::Ident(quote_ident!("verify")),
            function: Box::new(swc_ecma_ast::Function {
                params: vec![Param {
                    span: DUMMY_SP,
                    decorators: vec![],
                    pat: Pat::Ident(BindingIdent {
                        id: quote_ident!("message"),
                        type_ann: Some(Box::new(TsTypeAnn {
                            span: DUMMY_SP,
                            type_ann: Box::new(TsType::TsTypeRef(TsTypeRef {
                                span: DUMMY_SP,
                                type_name: TsEntityName::Ident(quote_ident!("Record")),
                                type_params: Some(Box::new(TsTypeParamInstantiation {
                                    span: DUMMY_SP,
                                    params: vec![
                                        Box::new(TsType::TsKeywordType(TsKeywordType {
                                            span: DUMMY_SP,
                                            kind: TsKeywordTypeKind::TsStringKeyword,
                                        })),
                                        Box::new(TsType::TsTypeRef(TsTypeRef {
                                            span: DUMMY_SP,
                                            type_name: TsEntityName::Ident(quote_ident!("ESObject")),
                                            type_params: None,
                                        })),
                                    ],
                                })),
                            })),
                        })),
                    }),
                }],
                decorators: vec![],
                span: DUMMY_SP,
                body: Some(swc_ecma_ast::BlockStmt {
                    span: DUMMY_SP,
                    stmts,
                }),
                is_generator: false,
                is_async: false,
                type_params: None,
                return_type: Some(Box::new(TsTypeAnn {
                    span: DUMMY_SP,
                    type_ann: Box::new(TsType::TsKeywordType(swc_ecma_ast::TsKeywordType {
                        span: DUMMY_SP,
                        kind: swc_ecma_ast::TsKeywordTypeKind::TsStringKeyword,
                    })),
                })),
            }),
            kind: MethodKind::Method,
            is_static: false,
            accessibility: Some(Accessibility::Public),
            is_abstract: false,
            is_optional: false,
            is_override: false,
        };
    
        // 定义 Verifier 类
        let class = Class {
            span: DUMMY_SP,
            decorators: vec![],
            body: vec![ClassMember::Method(verify_method)],
            super_class: None,
            is_abstract: false,
            type_params: None,
            super_type_params: None,
            implements: vec![implement],
        };
    
        ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
            span: DUMMY_SP,
            decl: Decl::Class(swc_ecma_ast::ClassDecl {
                ident: quote_ident!("$Verify"),
                declare: false,
                class: Box::new(class),
            }),
        }))
    }

    //verify
    pub fn verify_setup_inner(
        &self,
        ctx: &mut Context,
        descriptor: &DescriptorProto,
        ns: &mut Vec<String>,
    ) -> Vec<Stmt> {
        let mut stmts = vec![];
       
        // 检查必填字段、字段类型
        for field in &descriptor.field {
            if !field.has_oneof_index() {
                if field.label() != descriptor::field_descriptor_proto::Label::LABEL_REPEATED { // 非重复字段类型检查
                    stmts.push(self.check_field_type(ctx, field, ns));
                }
            } else {//处理oneof字段 todo
                
            }
        }
        
        // 添加返回 true 的默认语句
        stmts.push(Stmt::Return(ReturnStmt {
            span: DUMMY_SP,
            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                span: DUMMY_SP,
                value: format!("true").into(),
                raw: None,
            })))),
        }));
        
        stmts
    }

    fn check_field_type(
        &self,
        ctx: &mut Context,
        field: &FieldDescriptorProto,
        ns: &mut Vec<String>,
    ) -> Stmt {
        let utils = ctx.get_import_from(Self::RUNTIME_PACKAGE, Self::PB_UTILS_NAME);
        let field_ident = quote_ident!(normalize_name(field.name()));
        // 克隆 camel_case_name 以便多次使用
        let field_access = Box::new(Expr::Member(MemberExpr {
            span: DUMMY_SP,
            obj: Box::new(Expr::Ident(quote_ident!("message"))),
            prop: MemberProp::Ident(field_ident.clone()),
        }));
    
        // 主检查逻辑
        let field_check = Stmt::If(IfStmt {
            span: DUMMY_SP,
            test: Box::new(Expr::Bin(BinExpr {
                span: DUMMY_SP,
                left: Box::new(Expr::Bin(BinExpr {
                    span: DUMMY_SP,
                    left: field_access.clone(),
                    op: BinaryOp::NotEq,
                    right: Box::new(Expr::Ident(quote_ident!("undefined"))),
                })),
                op: BinaryOp::LogicalAnd,
                right: Box::new(Expr::Bin(BinExpr {
                    span: DUMMY_SP,
                    left: field_access.clone(),
                    op: BinaryOp::NotEqEq,
                    right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),
                })),
            })),
            cons: Box::new(match field.type_() {
                Type::TYPE_DOUBLE | Type::TYPE_FLOAT => {
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(Expr::Bin(BinExpr {
                            span: DUMMY_SP,
                            left: Box::new(Expr::Unary(UnaryExpr {
                                span: DUMMY_SP,
                                op: UnaryOp::TypeOf,
                                arg: field_access.clone(),
                            })),
                            op: BinaryOp::NotEqEq,
                            right: Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: "number".into(),
                                raw: None,
                            }))),
                        })),
                        cons: Box::new(Stmt::Return(ReturnStmt {
                            span: DUMMY_SP,
                            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: format!("{}: number expected", field_ident).into(),
                                raw: None,
                            })))),
                        })),
                        alt: None,
                    })
                },
                Type::TYPE_INT64 | Type::TYPE_UINT64 | Type::TYPE_INT32 | Type::TYPE_FIXED64 
                | Type::TYPE_FIXED32 | Type::TYPE_UINT32 | Type::TYPE_SFIXED32 
                | Type::TYPE_SFIXED64 | Type::TYPE_SINT32 | Type::TYPE_SINT64 => {
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(Expr::Unary(UnaryExpr {
                            span: DUMMY_SP,
                            op: UnaryOp::Bang,
                            arg: Box::new(Expr::Call(CallExpr {
                                span: DUMMY_SP,
                                callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
                                    span: DUMMY_SP,
                                    obj: Box::new(Expr::Ident(utils)),
                                    prop: MemberProp::Ident(quote_ident!("isInteger")),
                                }))),
                                args: vec![ExprOrSpread {
                                    spread: None,
                                    expr: field_access.clone(),
                                }],
                                type_args: None,
                            })),
                        })),
                        cons: Box::new(Stmt::Return(ReturnStmt {
                            span: DUMMY_SP,
                            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: format!("{}: integer expected", field_ident).into(),
                                raw: None,
                            })))),
                        })),
                        alt: None,
                    })
                },
                Type::TYPE_BOOL => {
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(Expr::Bin(BinExpr {
                            span: DUMMY_SP,
                            left: Box::new(Expr::Unary(UnaryExpr {
                                span: DUMMY_SP,
                                op: UnaryOp::TypeOf,
                                arg: field_access.clone(),
                            })),
                            op: BinaryOp::NotEqEq,
                            right: Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: "boolean".into(),
                                raw: None,
                            }))),
                        })),
                        cons: Box::new(Stmt::Return(ReturnStmt {
                            span: DUMMY_SP,
                            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: format!("{}: boolean expected", field_ident).into(),
                                raw: None,
                            })))),
                        })),
                        alt: None,
                    })
                },
                Type::TYPE_STRING => {
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(Expr::Bin(BinExpr {
                            span: DUMMY_SP,
                            left: Box::new(Expr::Unary(UnaryExpr {
                                span: DUMMY_SP,
                                op: UnaryOp::TypeOf,
                                arg: field_access.clone(),
                            })),
                            op: BinaryOp::NotEqEq,
                            right: Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: "string".into(),
                                raw: None,
                            }))),
                        })),
                        cons: Box::new(Stmt::Return(ReturnStmt {
                            span: DUMMY_SP,
                            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: format!("{}: string expected", field_ident).into(),
                                raw: None,
                            })))),
                        })),
                        alt: None,
                    })
                },
                Type::TYPE_BYTES => {
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(Expr::Bin(BinExpr {
                            span: DUMMY_SP,
                            left: Box::new(Expr::Unary(UnaryExpr {
                                span: DUMMY_SP,
                                op: UnaryOp::TypeOf,
                                arg: field_access.clone(),
                            })),
                            op: BinaryOp::NotEqEq,
                            right: Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: "object".into(),
                                raw: None,
                            }))),
                        })),
                        cons: Box::new(Stmt::Return(ReturnStmt {
                            span: DUMMY_SP,
                            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: format!("{}: Uint8Array expected", field_ident).into(),
                                raw: None,
                            })))),
                        })),
                        alt: None,
                    })
                },
                Type::TYPE_MESSAGE => {
                    // 先清理类型名称中可能存在的多余点
                    let cleaned_type = field.type_name().trim_start_matches('.');
                    let type_parts: Vec<&str> = cleaned_type.split('.').collect();
                    
                    // 确保至少有1个部分
                    if type_parts.is_empty() {
                        panic!("Invalid type name: {}", field.type_name());
                    }
                
                    // 构建基础表达式（第一个部分）
                    let mut member_expr = Expr::Ident(quote_ident!(type_parts[0].to_string()));
                    
                    // 添加剩余部分（确保不加多余的点）
                    for part in type_parts.iter().skip(1) {
                        member_expr = Expr::Member(MemberExpr {
                            span: DUMMY_SP,
                            obj: Box::new(member_expr),
                            prop: MemberProp::Ident(quote_ident!(part.to_string())),
                        });
                    }
                    
                    // 创建验证调用（确保路径正确）
                    let verify_call = Expr::Call(CallExpr {
                        span: DUMMY_SP,
                        callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
                            span: DUMMY_SP,
                            obj: Box::new(member_expr),
                            prop: MemberProp::Ident(quote_ident!("verify")),
                        }))),
                        args: vec![ExprOrSpread {
                            spread: None,
                            expr: field_access.clone(),
                        }],
                        type_args: None,
                    });
                
                    // 构建完整的if语句
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(verify_call), // 直接使用验证调用
                        cons: Box::new(Stmt::Block(BlockStmt {
                            span: DUMMY_SP,
                            stmts: vec![
                                Stmt::Return(ReturnStmt {
                                    span: DUMMY_SP,
                                    arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                        span: DUMMY_SP,
                                        value: format!("{}: invalid message type", field_ident).into(),
                                        raw: None,
                                    })))),
                                })
                            ],
                        })),
                        alt: None,
                    })
                },
                Type::TYPE_ENUM => {
                    Stmt::If(IfStmt {
                        span: DUMMY_SP,
                        test: Box::new(Expr::Bin(BinExpr {
                            span: DUMMY_SP,
                            left: Box::new(Expr::Unary(UnaryExpr {
                                span: DUMMY_SP,
                                op: UnaryOp::TypeOf,
                                arg: field_access.clone(),
                            })),
                            op: BinaryOp::NotEqEq,
                            right: Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: "number".into(),
                                raw: None,
                            }))),
                        })),
                        cons: Box::new(Stmt::Return(ReturnStmt {
                            span: DUMMY_SP,
                            arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
                                span: DUMMY_SP,
                                value: format!("{}: number expected for enum", field_ident).into(),
                                raw: None,
                            })))),
                        })),
                        alt: None,
                    })
                },
                _ => Stmt::Empty(EmptyStmt { span: DUMMY_SP }),
            }),
            alt: None,
        });
    
        field_check
    }
}